import { any, must } from "../core/logic";
import { Engine } from "../Engine";
import { Geometry } from "./Geometry";
import { atlasJsonLoader } from "../assets/loader/AtlasJsonLoader";
import { process } from "../process/worker/process";
/**
 * 材质类。
 * @class
 * @memberof w
 */
class TextGeometry extends Geometry {
    /**
        * 文字几何体的构造方法。
        * @constructor
        * @param {*} opts 
        * @param {boolean} opts.back 【选填】对文字的解析是否放在后台，缺省：true，在后台进行解析。
        * @param {object} opts.data 【必填】文字数据,多个点可用数组。
        * @param {array} opts.data.text 文字内容数据。
        * @param {array[]} opts.data.position 文字位置数据。
        * @param {array } opts.color 【选填】文字颜色值。
        * @param {string } opts.fontUrl 【必填】文字字体atlas.json文件所在路径。
        * @param {array } opts.fontSize 【选填】文字字体大小，缺省值：[12,12]。
        * @param {number } opts.width 【选填】文字容器像素宽度，缺省值：300。
        * @param {number|string } opts.height 【选填】文字容器像素高度，自适应高度时使用'auto', 缺省值：auto 。
        * @param {number } opts.lineHeight 【选填】文字行高，缺省值：30。
        * @param {number } opts.space 【选填】文字字符间距，缺省值：2。
        * @param {string } opts.overflow 【选填】文字溢出样式，可选值：ellipsis(省略号)，hidden(隐藏)，缺省值：ellipsis。
        * @param {string} opts.horizontalLocation 【选填】文字相对于位置中心的水平位置，可选值：left,center,right。缺省值：center。
        * @param {string} opts.verticalLocation 【选填】文字相对于位置中心的垂直位置，可选值：top,middle,bottom。缺省值：middle。
        * @param {string} opts.textAlign 【选填】文字在容器内水平居中方式，可选值：left,center,right。缺省值：center。
        * @param {string} opts.verticalAlign 【选填】文字在容器内垂直居中方式，可选值：top,middle,bottom。缺省值：middle。
        * @param {array} opts.relativeShift 【选填】文字相对于位置中心的偏移。缺省值：[0,0]。
        * @param {function} opts.callback 【选填】文字数据生成完成回调。
        */
    constructor(opts = {}, share) {
        super({ autoUpdate: false });
        this.type = "PointGeometry";
        this.geometryType = "PointGeometry";
        this._hash = "";
        this.rawColor = any(opts.color, new Float32Array([]));
        this.varySize = any(opts.varySize, false);
        this.promise = [];
        let camera = Engine.instance.scene.getCamera();
        let cameraDistance = camera.trans.position.distanceTo(camera.at)
        this.pixelRatio = cameraDistance * 2.309401076758503 / camera.size[1];
        this.pixelUnit=any(opts.pixelUnit,true);
        this.fontUrl = must(opts.fontUrl);
        this.fontSize = any(opts.fontSize, [12, 12]);
        this.width = any(opts.width, 300);
        this.height = any(opts.height, 'auto');
        this.lineHeight = any(opts.lineHeight, 30)
        this.horizontalLocation = any(opts.horizontalLocation, 'center');
        this.verticalLocation = any(opts.verticalLocation, 'middle');
        this.textAlign = any(opts.textAlign, 'center');
        this.verticalAlign = any(opts.verticalAlign, 'middle');
        this.space = any(opts.space, 2);
        this.overflow = any(opts.overflow, 'ellipsis');
        this.relativeShift = any(opts.relativeShift, [0, 0]);
        this.shape = any(opts.shape, 'rect');
        this.calcData = opts.calcData;
        this.processCallback = any(opts.callback, () => { })
        this.data = any(opts.data, []);

    }
    set pixelUnit(v) {
        if (this.pixelUnit !== v) {
            this._pixelUnit = v;
            this.addConfigParam("pixelUnit", v);
            this.update();
        }
        return this;
    }
    get pixelUnit() {
        return this._pixelUnit;
    }
    set data(v) {
        this._data = v;
        this.noRepeatPoints = v.position;
        if (this.fontInfo) {
            this.fillPosition();
        } else {
            Promise.all(this.promise).then(() => {
                this.fillPosition();
            })
        }
        return this;
    }
    get data() {
        return this._data;
    }
    set varySize(v) {
        this._varySize = v;
        this.addConfigParam("pointSizeVarying", v);
        return this;
    }
    get varySize() {
        return this._varySize;
    }
    set fontUrl(v) {
        this._fontUrl = v;
        const loader = atlasJsonLoader.load(v).then((atlas) => {
            let fontInfo = atlas ? atlas.info : undefined;
            if (atlas) {
                fontInfo = atlas.info;
            }
            this.fontInfo = fontInfo;

        })
        this.promise.push(loader);
        return this;
    }
    /**
     * @property {String} text  url 文字图集(路径)。/atlas.json atlas.png。
     */
    get fontUrl() {
        return this._fontUrl;
    }
    set fontInfo(v) {
        this._fontInfo = v;
        return this;
    }
    /**
     * @property {String} text  url 文字图集(路径)。/atlas.json atlas.png。
     */
    get fontInfo() {
        return this._fontInfo;
    }
    set fontSize(v) {
        this._fontSize = v;
        this.addParam("pointSize");
        return this;
    }
    get fontSize() {
        return this._fontSize;
    }
    set width(v) {
        this._width = v;
        return this;
    }
    get width() {
        return this._width;
    }
    set height(v) {
        this._height = v;
        return this;
    }
    get height() {
        return this._height;
    }
    set lineHeight(v) {
        this._lineHeight = v;
        return this;
    }
    get lineHeight() {
        return this._lineHeight;
    }
    set textAlign(v) {
        this._textAlign = v;
        return this;
    }
    get textAlign() {
        return this._textAlign;
    }
    set verticalAlign(v) {
        this._verticalAlign = v;
        return this;
    }
    get verticalAlign() {
        return this._verticalAlign;
    }
    set space(v) {
        this._space = v;
        return this;
    }
    get space() {
        return this._space;
    }
    set overflow(v) {
        this._overflow = v;
        return this;
    }
    get overflow() {
        return this._overflow;
    }

    set horizontalLocation(v) {
        this._horizontalLocation = v;
        return this;
    }
    get horizontalLocation() {
        return this._horizontalLocation;
    }
    set verticalLocation(v) {
        this._verticalLocation = v;
        return this;
    }
    get verticalLocation() {
        return this._verticalLocation;
    }
    set pointNormal(v) {
        this._pointNormal = v;
        this.addParam("pointNormal");
        return this;
    }
    get pointNormal() {
        return this._pointNormal;
    }
    set offset(v) {
        this._offset = v;
        this.addParam("offset");
        return this;
    }
    get offset() {
        return this._offset;
    }
    set relativeShift(v) {
        this._relativeShift = v;
        this.addParam("relativeShift");
        return this;
    }
    get relativeShift() {
        return this._relativeShift;
    }


    getPoints() {
        let noRepeatPoints = [];
        for (var j = 0; j < this.rawPosition.length; j += 3) {
            if (!(noRepeatPoints[noRepeatPoints.length - 1] && this.comparePoint(noRepeatPoints[noRepeatPoints.length - 1], [this.rawPosition[j], this.rawPosition[j + 1], this.rawPosition[j + 2]]))) {
                noRepeatPoints.push([this.rawPosition[j], this.rawPosition[j + 1], this.rawPosition[j + 2]])
            }
        }
        return noRepeatPoints;
    }
    fillPosition() {
        if (this.calcData) {
            let {
                positions,
                offsets,
                indices_array,
                directions,
                uvs,
                colors,
            } = this.calcData;
            this.indices = indices_array;
            this.position = positions;
            this.offset = offsets;
            this.pointNormal = directions;
            this.texCood0 = uvs;
            if (colors.length) {
                this.color = colors;
            }
            this.autoUpdate = true;
            this.update();
            this.processCallback(message.data);
        } else {
            process({
                type: "text",
                back: this.back,
                data: this.data,
                color: this.rawColor,
                fontInfo: this.fontInfo,
                fontSize: this.fontSize,
                width: this.width,
                height: this.height,
                lineHeight: this.lineHeight,
                horizontalLocation: this.horizontalLocation,
                verticalLocation: this.verticalLocation,
                textAlign: this.textAlign,
                verticalAlign: this.verticalAlign,
                space: this.space,
                overflow: this.overflow,
                varySize: this.varySize,
                pixelRatio: this.pixelRatio,
            }, (message) => {
                let {
                    positions,
                    offsets,
                    indices_array,
                    directions,
                    uvs,
                    colors,
                } = message.data;
                this.indices = indices_array;
                this.position = positions;
                this.offset = offsets;
                this.pointNormal = directions;
                this.texCood0 = uvs;
                if (colors.length) {
                    this.color = colors;
                }
                this.autoUpdate = true;
                this.update();
                this.processCallback(message.data);
            })
        }

    }

    toGPU() {
        if (this.has("pointSize")) {
            let data = [...this.fontSize];
            if (this.varySize) {
                data = data.map(item => item * this.pixelRatio);
            }
            this.bufferToGPU(new Float32Array(data), 'pointSize', GPUShaderStage.VERTEX);
        }
        if (this.has("pointNormal")) {
            this.initVertex(this.pointNormal, "pointNormal", 3);
        }
        if (this.has("offset")) {
            this.initVertex(this.offset, "offset", 2);
        }
        if (this.has("relativeShift")) {
            let data = [...this.relativeShift];
            if (this.varySize) {
                data = data.map(item => item * this.pixelRatio);
            }
            this.bufferToGPU(new Float32Array(data), 'relativeShift', GPUShaderStage.VERTEX);
        }
        super.toGPU();
    }




}

export { TextGeometry };
